import { Stage, Layer, Group, Image, Rect, Path, Line, Text } from "konva";
import scoreUnderline from "@/assets/paper-trace/score-underline.png";
import orderDefaultBg from "@/assets/paper-trace/order-default-bg.png";
import cnSentenceSelectBg from "@/assets/paper-trace/cn-sentence-sel.png";
import cnParagraphSelectBg from "@/assets/paper-trace/cn-paragraph-sel.png";
import enSentenceSelectBg from "@/assets/paper-trace/en-sentence-sel.png";
import { capitalizeWord, loadImage } from "./utils";

//DONE
// 1. 支持英语学科波浪线颜色 √
// 2. emits mark 点击事件 √
// 3. 序号绘制 √
// 5. 组件中要有只渲染打分的逻辑 √
// 8. 序号渲染逻辑抽离，可单独调用 √
// 7. 序号要在不同视图显示 √
// 9. 监听容器高度变化，并适配对应高度，显示区域不能发送变化 √
// 4. 切换高亮时，序号不重新渲染，用渐变修改（无法实现，序号属于mark子元素，元素现在是删除渲染的逻辑，所以无法做） ×
// 10. 支持切换 viewType 时，mark 事件绑定和解绑 √
// 6. 高亮时，高亮的mark滚动到屏幕中间位置 √
// 12. 惯性滑动 √
// 13. 项目正式流程模拟 √

//TODO:
// 14. B端横版-排列适配 √
// 15. B端横版-高度自适应 √
// 15. B端横版-滚动到视口要有横版的逻辑（暂不做横版的滚动逻辑）
// 15. B端横版-分数显示在右上角 √
// 15. B端横版-处理PC端拖拽，event与H5不一样 √

class EssayEvaluator {
    constructor(options) {
        this.subject = options?.subject || "chinese"; // 学科
        this.dir = options?.dir || "vertical"; // 当前默认竖向是h5，横向是pc

        this.stage = null; // 舞台
        this.imageLayer = null; // 图片层
        this.imageGroup = null; // 图片组
        this.imageGroupConfig = {}; // 图片组配置
        this.mainLayer = null; // 上层
        this.mainGroup = null; // 上层组
        this.mainGroupConfig = {}; // 上层组配置
        this.wordGroup = null; // 单词组
        this.sentenceGroup = null; // 句子组
        this.paragraphGroup = null; // 段落组
        this.correctionGroup = null; // 智能纠错组
        this.scoreGroup = null; // 分数组
        this.wordList = null; // 单词数据列表
        this.sentenceList = null; // 句子数据列表
        this.correctionList = null; // 智能纠错数据列表
        this.paragraphList = null; // 段落数据列表
        this.wordzIndex = 10;
        this.sentencezIndex = 5;
        this.paragraphzIndex = 5;
        this.correctionzIndex = 5;
        this.scorezIndex = 100;

        this.scale = 1; // 当前缩放比例
        this.minScale = 1; // 最小缩放比例
        this.maxScale = 3; // 最大缩放比例
        this.isDragging = false; // 是否正在拖动
        this.isPinching = false; // 是否正在缩放
        this.lastTouchPos = { x: 0, y: 0 }; // 上次触摸位置
        this.lastTouchDistance = 0; // 上次触摸距离
        this.lastTouchCenter = { x: 0, y: 0 }; // 上次触摸中心

        // 惯性滑动相关变量
        this.velocityX = 0;
        this.velocityY = 0;
        this.lastMoveTime = 0;
        this.interiaAnimationId = null;

        this.wordRectStrokeWidth = 3; // 单词矩形边框宽度
        this.underlineStrokeWidth = 3; // 波浪线和下划线宽度

        this.renderWordsFunc = this.renderWords.bind(this);
        this.renderSentencesFunc = this.renderSentences.bind(this);
        this.renderParagraphsFunc = this.renderParagraphs.bind(this);
        this.renderCorrectionsFunc = this.renderCorrections.bind(this);
        this.handleTouchstartFunc = this.handleTouchstart.bind(this);
        this.handleTouchmoveFunc = this.handleTouchmove.bind(this);
        this.handleTouchendFunc = this.handleTouchend.bind(this);

        this.onMarkClick = options?.onMarkClick || (() => {});
    }

    initStage(config) {
        const { container, width, height } = config;

        this.stage = new Stage({
            container,
            width,
            height,
        });
    }

    initLayer(config) {
        this.initImageLayer(config);
        this.initMainLayer(config);
    }

    initImageLayer(groupConfig) {
        this.imageLayer = new Layer();
        this.stage.add(this.imageLayer);

        this.imageGroup = new Group(groupConfig);
        this.imageLayer.add(this.imageGroup);

        this.imageGroupConfig = groupConfig;
    }

    initMainLayer(groupConfig) {
        this.mainLayer = new Layer();
        this.stage.add(this.mainLayer);

        this.mainGroup = new Group(groupConfig);
        this.mainLayer.add(this.mainGroup);

        this.mainGroupConfig = groupConfig;
    }
    // 高度动态调试适配
    adaptHeight(height) {
        this.stage.height(height);
        this.limitPosition();
    }

    renderBgImages(list) {
        for (let i = 0; i < list.length; i++) {
            const { img, x, y, width, height } = list[i];
            const image = new Image({
                x,
                y,
                width,
                height,
                image: img,
            });
            this.imageGroup.add(image);
        }
    }

    renderMask(config) {
        const { mainGroup } = this;
        const mask = new Rect({
            x: 0,
            y: 0,
            width: mainGroup.width(),
            height: mainGroup.height(),
            fill: "rgba(0,0,0,0.2)",
            ...config,
        });
        mainGroup.add(mask);
    }

    renderWords(list = []) {
        if (!this.wordGroup) {
            this.wordGroup = new Group({ name: "wordGroup" });
            this.mainGroup.add(this.wordGroup);
        }
        this.wordList = list;
        for (let i = 0; i < list.length; i++) {
            const item = list[i];
            const { isHighlight, cooridates } = item;
            const group = new Group({
                name: "wordGroupItem",
                index: i,
            });
            for (let j = 0; j < cooridates.length; j++) {
                const cooridate = cooridates[j];
                const { x, y, width, height } = cooridate;
                const rectInteraction = createInteractionRect({
                    name: "interaction",
                    ...cooridate,
                    opacity: isHighlight ? 1 : 0,
                });
                const rectFrame = new Rect({
                    x,
                    y,
                    width,
                    height,
                    stroke: "#FFB10B",
                    strokeWidth: this.wordRectStrokeWidth,
                });
                group.add(rectInteraction);
                group.add(rectFrame);
            }
            this.wordGroup.add(group);
        }
        this.setMarkZIndex();
    }

    renderSentences(list = []) {
        if (!this.sentenceGroup) {
            this.sentenceGroup = new Group({ name: "sentenceGroup" });
            this.mainGroup.add(this.sentenceGroup);
        }
        this.sentenceList = list;
        for (let i = 0; i < list.length; i++) {
            const item = list[i];
            const { isHighlight, cooridates } = item;
            const group = new Group({
                name: "sentenceGroupItem",
                index: i,
            });

            const interactionGroup = new Group({
                name: "interactionGroup",
                opacity: isHighlight ? 1 : 0,
            }); // 高亮交互组
            const waveLineGroup = new Group({ name: "waveLineGroup" }); // 波浪线组

            for (let j = 0; j < cooridates.length; j++) {
                const cooridate = cooridates[j];
                const { x, y, width, height } = cooridate;
                const rectInteraction = createInteractionRect({
                    name: "interaction",
                    ...cooridate,
                });
                interactionGroup.add(rectInteraction);

                const wavePath = new Path(
                    createWaveLineConfig({
                        x,
                        y,
                        width,
                        height,
                        strokeWidth: this.underlineStrokeWidth,
                        stroke: "#23E067",
                    })
                );
                waveLineGroup.add(wavePath);
            }
            group.add(interactionGroup);
            group.add(waveLineGroup);
            this.sentenceGroup.add(group);
        }
        this.setMarkZIndex();
    }
    // 渲染段落
    renderParagraphs(list = []) {
        if (!this.paragraphGroup) {
            this.paragraphGroup = new Group({ name: "paragraphGroup" });
            this.mainGroup.add(this.paragraphGroup);
        }
        this.paragraphList = list;
        for (let i = 0; i < list.length; i++) {
            const item = list[i];
            const { isHighlight, cooridates } = item;
            const group = new Group({
                name: "paragraphGroupItem",
                index: i,
            });

            const interactionGroup = new Group({
                opacity: isHighlight ? 1 : 0,
            }); // 高亮交互组
            const underLineGroup = new Group();

            for (let j = 0; j < cooridates.length; j++) {
                const cooridate = cooridates[j];
                const rectInteraction = createInteractionRect({
                    name: "interaction",
                    ...cooridate,
                });
                interactionGroup.add(rectInteraction);

                const underLine = new Line(
                    createUnderLineConfig({
                        ...cooridate,
                        strokeWidth: this.underlineStrokeWidth,
                    })
                );
                underLineGroup.add(underLine);

                group.add(interactionGroup);
                group.add(underLineGroup);
                this.paragraphGroup.add(group);
            }
        }
        this.setMarkZIndex();
    }
    // 渲染智能纠错
    renderCorrections(list = []) {
        if (!this.correctionGroup) {
            this.correctionGroup = new Group({ name: "correctionGroup" });
            this.mainGroup.add(this.correctionGroup);
        }
        this.correctionList = list;
        for (let i = 0; i < list.length; i++) {
            const item = list[i];
            const { isHighlight, cooridates } = item;
            const group = new Group({
                name: "correctionGroupItem",
                index: i,
            });

            const interactionGroup = new Group({
                name: "interactionGroup",
                opacity: isHighlight ? 1 : 0,
            }); // 高亮交互组
            const waveLineGroup = new Group({ name: "waveLineGroup" }); // 波浪线组

            for (let j = 0; j < cooridates.length; j++) {
                const cooridate = cooridates[j];
                const { x, y, width, height } = cooridate;
                const rectInteraction = createInteractionRect({
                    name: "interaction",
                    ...cooridate,
                });
                interactionGroup.add(rectInteraction);

                const wavePath = new Path(
                    createWaveLineConfig({
                        x,
                        y,
                        width,
                        height,
                        strokeWidth: this.underlineStrokeWidth,
                        stroke: "#FF1717",
                    })
                );
                waveLineGroup.add(wavePath);
            }
            group.add(interactionGroup);
            group.add(waveLineGroup);
            this.correctionGroup.add(group);
        }
        this.setMarkZIndex();
    }
    // 渲染指定类型mark的序号
    async renderOrderNumber(type) {
        const topGroup = this[`${type}Group`];
        const list = this[`${type}List`];
        if (!list || !list.length) return;
        for (let i = 0; i < list.length; i++) {
            const item = list[i];
            const parentGroup = topGroup.children[i];
            const isHighlight = item.isHighlight;
            const cooridate = item.cooridates[0];
            if (!cooridate) continue;
            const { x, y } = cooridate;
            const bgImg = await this.getOrderNumberBg(type, isHighlight);
            const width = 24;
            const height = (width * bgImg.height) / bgImg.width;
            const group = new Group({
                name: `${type}OrderNumberGroup`,
                x: x - width / 2,
                y: y - 6,
                visible: true,
            });
            const bgImage = new Image({
                image: bgImg,
                x: 0,
                y: 0,
                width,
                height,
            });
            const text = new Text({
                x: 0,
                y: 0,
                width,
                height,
                align: "center",
                verticalAlign: "middle",
                text: i + 1,
                fontSize: width / 1.5,
                fill: "#fff",
            });

            group.add(bgImage);
            group.add(text);
            parentGroup.add(group);
        }
        this.mainLayer.batchDraw();
    }
    // 获取序号背景图片
    async getOrderNumberBg(type, isHighlight) {
        if (type === "paragraph") {
            return await loadImage(
                isHighlight ? cnParagraphSelectBg : orderDefaultBg
            );
        } else if (type === "sentence") {
            return await loadImage(
                isHighlight ? cnSentenceSelectBg : orderDefaultBg
            );
        } else if (type === "correction") {
            return await loadImage(
                isHighlight ? enSentenceSelectBg : orderDefaultBg
            );
        }
    }
    // 清除指定类型mark的序号
    clearOrderNumber(...types) {
        for (let type of types) {
            const topGroup = this[`${type}Group`];
            if (!topGroup) continue;
            const len = topGroup.children.length;
            for (let i = 0; i < len; i++) {
                const parentGroup = topGroup.children[i];
                const orderNumberGroup = parentGroup.children.find((node) =>
                    /ordernumber/i.test(node.name())
                );
                orderNumberGroup && orderNumberGroup.destroy();
            }
        }
    }
    // 渲染分数
    async renderScore(score) {
        if (!this.scoreGroup) {
            this.scoreGroup = new Group({
                name: "scoreGroup",
            });
            this.mainGroup.add(this.scoreGroup);
        }
        const scoreText = new Text({
            fontSize: 50,
            fontFamily: "Muyao",
            fill: "#D81E06",
            listening: false,
            text: score,
        });

        const scoreUnderlineImage = await loadImage(scoreUnderline);
        const imageConfig = this.calUnderlineImageConfig(
            scoreText,
            scoreUnderlineImage
        );
        const image = new Image(imageConfig);
        // 分数默认渲染在右上角
        this.scoreGroup.x(this.mainGroup.width() - image.width());
        this.scoreGroup.add(image);
        this.scoreGroup.add(scoreText);
        this.setMarkZIndex();
    }
    // 计算分数下划线图片的配置
    calUnderlineImageConfig(scoreText, img) {
        const scale = 1.8;
        const scoreTextWidth = scoreText.width();
        const scoreTextHeight = scoreText.height();
        const underlineWidth = scoreTextWidth * scale;
        const underlineHeight = underlineWidth * (img.height / img.width);
        const imageConfig = {
            image: img,
            x: -scoreTextWidth / scale + 10,
            y: scoreTextHeight,
            width: underlineWidth,
            height: underlineHeight,
        };
        return imageConfig;
    }
    setMarkZIndex() {
        this.wordGroup && this.wordGroup.zIndex(this.wordzIndex);
        this.sentenceGroup && this.sentenceGroup.zIndex(this.sentencezIndex);
        this.paragraphGroup && this.paragraphGroup.zIndex(this.paragraphzIndex);
        this.correctionGroup &&
            this.correctionGroup.zIndex(this.paragraphzIndex);
        this.scoreGroup && this.scoreGroup.zIndex(this.scorezIndex);
    }
    // 绑定标注事件
    bindMarkEvent(...types) {
        for (let i = 0; i < types.length; i++) {
            const type = types[i];
            const group = this[`${type}Group`];
            const list = this[`${type}List`];
            const func = this[`render${capitalizeWord(type)}sFunc`];

            group && this.bindTapClickEvent(group, list, func);
        }
    }
    // 解绑标注事件
    unBindMarkEvent(...types) {
        for (let i = 0; i < types.length; i++) {
            const type = types[i];
            const group = this[`${type}Group`];
            const func = this[`render${capitalizeWord(type)}sFunc`];

            group && group.off("tap click", func);
        }
    }
    // 绑定点击事件
    bindTapClickEvent(node, list, renderFunc) {
        const markType = node.name().slice(0, -5);
        node.on("tap click", (e) => {
            const groupItem = findUpwardNode(e.target, `${node.name()}Item`);
            if (groupItem) {
                const { index } = groupItem;
                let currentItem = null;
                for (let i = 0; i < list.length; i++) {
                    const item = list[i];
                    item.isHighlight = false;
                    if (i === index) {
                        item.isHighlight = true;
                        currentItem = item;
                    }
                }
                node.destroyChildren();
                renderFunc && renderFunc(list);
                if (markType !== "word") {
                    this.renderOrderNumber(markType);
                }
                this.scrollToView(markType, groupItem.attrs.index);
                this.onMarkClick && this.onMarkClick(markType, currentItem);
            }
        });
    }
    // 绑定滑动和缩放事件
    bindDragAndScaleEvent() {
        const { stage } = this;
        stage.on("touchstart mousedown", this.handleTouchstartFunc);
        stage.on("touchmove mousemove", this.handleTouchmoveFunc);
        stage.on("touchend mouseup", this.handleTouchendFunc);
        stage.on("touchcancel mouseleave", this.handleTouchendFunc);
    }
    // 解绑滑动和缩放事件
    unBindDragAndScaleEvent() {
        const { stage } = this;
        stage.off("touchstart", this.handleTouchstartFunc);
        stage.off("touchmove", this.handleTouchmoveFunc);
        stage.off("touchend", this.handleTouchendFunc);
        stage.off("touchcancel", this.handleTouchendFunc);
    }
    // 处理事件兼容
    getEventTouches(e) {
        // return this.dir === "vertical" ? e.evt.touches : [e.evt];
        return e.evt.touches || [e.evt];
    }
    // 处理触摸开始事件
    handleTouchstart(e) {
        e.evt.preventDefault(); // 阻止默认行为

        // 如果有惯性动画正在进行，取消它
        if (this.inertiaAnimationId !== null) {
            cancelAnimationFrame(this.inertiaAnimationId);
            this.inertiaAnimationId = null;
        }

        const touches = this.getEventTouches(e);
        if (touches.length === 1) {
            // 单指触摸 - 准备拖动
            this.isDragging = true;
            this.isPinching = false;
            // 记录触摸起始位置
            this.lastTouchPos = {
                x: touches[0].clientX,
                y: touches[0].clientY,
            };

            this.lastMoveTime = Date.now();
            this.velocityX = 0;
            this.velocityY = 0;
        } else if (touches.length === 2) {
            // 双指触摸 - 准备缩放
            this.isPinching = true;
            this.isDragging = false;

            // 计算两指间的距离和中心点
            const touch1 = touches[0];
            const touch2 = touches[1];

            this.lastTouchCenter = {
                x: (touch1.clientX + touch2.clientX) / 2,
                y: (touch1.clientY + touch2.clientY) / 2,
            };

            this.lastTouchDistance = Math.sqrt(
                Math.pow(touch2.clientX - touch1.clientX, 2) +
                    Math.pow(touch2.clientY - touch1.clientY, 2)
            );
        }
    }
    // 处理触摸移动事件
    handleTouchmove(e) {
        e.evt.preventDefault(); // 阻止默认行为

        const {
            mainLayer,
            imageLayer,
            mainGroup,
            imageGroup,
            lastTouchPos,
            lastTouchCenter,
            lastTouchDistance,
            maxScale,
            minScale,
            scale,
        } = this;
        const touches = this.getEventTouches(e);
        if (touches.length === 1 && this.isDragging) {
            // 单指触摸移动 - 处理拖动
            const currentPos = {
                x: touches[0].clientX,
                y: touches[0].clientY,
            };

            // 计算移动距离
            const dx = currentPos.x - lastTouchPos.x;
            const dy = currentPos.y - lastTouchPos.y;
            const tox = imageGroup.x() + dx;
            const toy = imageGroup.y() + dy;

            const currentTime = Date.now();
            const timeElapsed = currentTime - this.lastMoveTime;

            // 计算速度 (像素/毫秒)
            if (timeElapsed > 0) {
                this.velocityX = dx / timeElapsed;
                this.velocityY = dy / timeElapsed;
            }

            // 应用移动
            imageGroup.position({
                x: tox,
                y: toy,
            });

            // 同步遮罩的移动
            mainGroup.position({
                x: tox,
                y: toy,
            });

            // 更新上一次触摸位置
            this.lastTouchPos = currentPos;
            this.lastMoveTime = currentTime;

            // 应用边界限制
            this.limitPosition();
            imageLayer.batchDraw();
            mainLayer.batchDraw();
        } else if (touches.length === 2 && this.isPinching) {
            // 双指触摸移动 - 处理缩放
            const touch1 = touches[0];
            const touch2 = touches[1];

            // 计算新的中心点和距离
            const currentCenter = {
                x: (touch1.clientX + touch2.clientX) / 2,
                y: (touch1.clientY + touch2.clientY) / 2,
            };

            const currentDistance = Math.sqrt(
                Math.pow(touch2.clientX - touch1.clientX, 2) +
                    Math.pow(touch2.clientY - touch1.clientY, 2)
            );

            if (lastTouchDistance > 0) {
                // 计算缩放因子
                const scaleFactor = currentDistance / lastTouchDistance;

                // 计算新的缩放比例
                const newScale = Math.max(
                    minScale,
                    Math.min(maxScale, scale * scaleFactor)
                );

                if (newScale !== scale) {
                    // 计算缩放中心点在图片组上的相对位置
                    const centerPointOnGroup = {
                        x: (lastTouchCenter.x - imageGroup.x()) / scale,
                        y: (lastTouchCenter.y - imageGroup.y()) / scale,
                    };

                    // 应用新的缩放比例
                    imageGroup.scale({ x: newScale, y: newScale });
                    mainGroup.scale({ x: newScale, y: newScale });

                    // 调整位置，使缩放中心点保持在双指中心
                    const posX =
                        currentCenter.x - centerPointOnGroup.x * newScale;
                    const posY =
                        currentCenter.y - centerPointOnGroup.y * newScale;
                    imageGroup.position({
                        x: posX,
                        y: posY,
                    });
                    mainGroup.position({
                        x: posX,
                        y: posY,
                    });

                    this.scale = newScale;
                }

                // 处理平移
                const dx = currentCenter.x - lastTouchCenter.x;
                const dy = currentCenter.y - lastTouchCenter.y;

                if (dx !== 0 || dy !== 0) {
                    const tx = imageGroup.x() + dx;
                    const ty = imageGroup.y() + dy;
                    imageGroup.position({
                        x: tx,
                        y: ty,
                    });
                    // 同步遮罩的平移
                    mainGroup.position({
                        x: tx,
                        y: ty,
                    });
                }

                // 更新上一次的中心点和距离
                this.lastTouchCenter = currentCenter;
                this.lastTouchDistance = currentDistance;

                // 应用边界限制
                this.limitPosition();
                imageLayer.batchDraw();
                mainLayer.batchDraw();
            }
        }
    }
    // 处理触摸结束事件
    handleTouchend(e) {
        const touches = this.getEventTouches(e);
        if (touches.length === 1) {
            // 从双指变为单指
            this.isPinching = false;
            this.isDragging = false;

            // 记录新的触摸位置
            this.lastTouchPos = {
                x: touches[0].clientX,
                y: touches[0].clientY,
            };

            // 应用边界限制
            this.limitPosition();
            this.imageLayer.batchDraw();
            this.mainLayer.batchDraw();
        } else {
            if (
                this.isDragging &&
                (Math.abs(this.velocityX) > 0.05 ||
                    Math.abs(this.velocityY) > 0.05)
            ) {
                this.startInertiaAnimation();
            }

            this.isPinching = false;
            this.isDragging = false;
            this.lastTouchCenter = { x: 0, y: 0 };
            this.lastTouchDistance = 0;
        }
    }
    // 限制滑动边界
    limitPosition() {
        const { imageGroup, mainGroup, stage, scale } = this;
        const groupWidth = imageGroup.width() * scale;
        const groupHeight = imageGroup.height() * scale;
        const stageWidth = stage.width();
        const stageHeight = stage.height();

        let x = imageGroup.x();
        let y = imageGroup.y();

        // 水平方向限制
        if (groupWidth <= stageWidth) {
            // 如果图片组宽度小于舞台宽度，则水平居中
            x = (stageWidth - groupWidth) / 2;
        } else {
            // 否则限制在边界内
            const minX = stageWidth - groupWidth;
            const maxX = 0;
            x = Math.max(minX, Math.min(maxX, x));
        }

        // 垂直方向限制
        if (groupHeight <= stageHeight) {
            // 如果图片组高度小于舞台高度，则垂直居中
            y = (stageHeight - groupHeight) / 2;
        } else {
            // 否则限制在边界内
            const minY = stageHeight - groupHeight;
            const maxY = 0;
            y = Math.max(minY, Math.min(maxY, y));
        }

        // 应用新位置
        imageGroup.position({ x, y });
        mainGroup.position({ x, y });
    }
    // 惯性滑动函数
    startInertiaAnimation() {
        const friction = 0.95; // 摩擦系数，数值越小减速越快
        const minVelocity = 0.01; // 最小速度阈值，低于此值停止动画

        const animate = () => {
            const {
                mainLayer,
                imageLayer,
                imageGroup,
                mainGroup,
                velocityX,
                velocityY,
            } = this;

            // 如果速度足够小，停止动画
            if (
                Math.abs(velocityX) < minVelocity &&
                Math.abs(velocityY) < minVelocity
            ) {
                this.inertiaAnimationId = null;
                return;
            }

            // 应用移动
            imageGroup.position({
                x: imageGroup.x() + velocityX * 16, // 假设16ms一帧
                y: imageGroup.y() + velocityY * 16,
            });

            // 同步遮罩的移动
            mainGroup.position({
                x: mainGroup.x() + velocityX * 16,
                y: mainGroup.y() + velocityY * 16,
            });

            // 应用边界限制
            this.limitPosition();

            // 应用摩擦力减速
            this.velocityX *= friction;
            this.velocityY *= friction;

            // 绘制图层
            imageLayer.batchDraw();
            mainLayer.batchDraw();

            // 继续动画
            this.inertiaAnimationId = requestAnimationFrame(animate);
        };

        this.inertiaAnimationId = requestAnimationFrame(animate);
    }
    // 清除全部mark
    clearAllMark() {
        ["word", "sentence", "paragraph", "score"].forEach((type) => {
            this.clearMark(type);
        });
    }
    // 清除mark
    clearMark(...types) {
        for (let i = 0; i < types.length; i++) {
            const type = types[i];
            const group = this[`${type}Group`];
            const list = this[`${type}List`];
            if (group) {
                // 删除所有子元素
                group.destroyChildren();
            }
            if (list) {
                // 去除高亮状态
                list.forEach((item) => (item.isHighlight = false));
            }
        }
    }
    // 取消高亮并重新渲染
    cancelMarkHighlight(...types) {
        for (let type of types) {
            const group = this[`${type}Group`];
            const list = this[`${type}List`];
            const renderFunc = this[`render${capitalizeWord(type)}sFunc`];

            if (!list || !group || !renderFunc) return;

            list.forEach((item) => (item.isHighlight = false));
            group.destroyChildren();
            renderFunc(list);
        }
    }
    // 将内容滚动到视口范围内
    scrollToView(markType, index) {
        if (this.dir === "vertical") {
            this.scrollToViewVertical(markType, index);
        } else {
            // 暂不让横向滚动
            // this.scrollToViewHorizontal(markType, index);
        }
    }
    scrollToViewVertical(markType, index) {
        const { stage, mainGroup, imageGroup, scale } = this;
        const list = this[`${markType}List`];
        const nodeY = list[index].cooridates[0].y * scale;
        const stageHeight = stage.height();
        const scrollY = mainGroup.y() * scale;
        const middleY = Math.abs(scrollY) + stageHeight / 3;
        const diffY = nodeY - middleY;
        const maxY = 0;
        const minY = stageHeight - mainGroup.height() * scale;
        const targetY = Math.max(minY, Math.min(maxY, scrollY - diffY));

        mainGroup.to({ y: targetY, duration: 0.3 });
        imageGroup.to({ y: targetY, duration: 0.3 });
    }
    //TODO:位置计算的不对
    scrollToViewHorizontal(markType, index) {
        const { stage, mainGroup, imageGroup, scale } = this;
        const list = this[`${markType}List`];
        const nodeX = list[index].cooridates[0].x * scale;
        const stageWidth = stage.width();
        const scrollX = mainGroup.x() * scale;
        const middleX = Math.abs(scrollX) + stageWidth / 3;
        const diffX = nodeX - middleX;
        const maxX = 0;
        const minX = stageWidth - mainGroup.width() * scale;
        const targetX = Math.max(minX, Math.min(maxX, scrollX - diffX));

        mainGroup.to({ x: targetX, duration: 0.3 });
        imageGroup.to({ x: targetX, duration: 0.3 });
    }
}

// 创建高亮交互区域
function createInteractionRect({ x, y, width, height, opacity = 1 }) {
    return new Rect({
        x,
        y,
        width,
        height,
        fill: "rgba(0,0,0,1)",
        globalCompositeOperation: "destination-out",
        opacity,
    });
}
// 创建波浪线
function createWaveLineConfig({
    x: startX,
    y: startY,
    width,
    height,
    strokeWidth,
    ...restConfig
}) {
    // 定义波浪路径参数
    const amplitude = 1.5; // 振幅：波峰的高度
    const frequency = 0.35; // 频率：波的密度（数值越大，波越密集）
    let pathData = "";

    for (let x = startX; x <= startX + width; x++) {
        // 控制路径点的密度
        const y = amplitude * Math.sin(x * frequency);
        const relX = x;
        const relY = startY + y + height + 2; // 2 为波浪线的偏移量
        pathData += x === 0 ? `M ${relX},${relY}` : ` L ${relX},${relY}`;
    }

    return {
        data: pathData,
        stroke: "#23E067", // 绿色
        strokeWidth,
        lineCap: "round", // 圆角端点
        ...restConfig,
    };
}
// 创建下划线
function createUnderLineConfig({ x, y, width, height, strokeWidth }) {
    const deviation = 3; // 偏差
    const endX = x + width;
    const endY = y + height + deviation;

    return {
        points: [x, endY, endX, endY],
        stroke: "#71F0FF",
        strokeWidth,
    };
}
// 向上级寻找对应 name 的节点
function findUpwardNode(node, name) {
    if (node.name() === name) {
        return node;
    }
    if (node.parent) {
        return findUpwardNode(node.parent, name);
    }
    return null;
}

export default EssayEvaluator;
